#include "Sphere.h"

bool Sphere::intersect(const Ray &ray, IntersectResult &result) const {
	Double t0, t1;
	Vector3 L = ray.origin - center;
	Double a = ray.dir.lengthSqr();
	Double b = 2 * (ray.dir * L);
	Double c = L.lengthSqr() - radiusSqr;
	if (!MathUtils::solveQuadratic(a, b, c, t0, t1)) return false;

	if (t0 > t1) SWAP(t0, t1);
	if (t0 < EPS) {
		t0 = t1; // if t0 is negative, let's use t1 instead 
		if (t0 < EPS) return false; // both t0 and t1 are negative 
	}

	result.primitive = this;
	result.distance = t0;
	result.position = ray.getPoint(t0);
	result.normal = result.position - center;
	result.normal.normalize();

	// compute UV
	Double phi = atan2(result.normal.z, result.normal.x);
	Double theta = asin(result.normal.y);
	result.uv.x = 1 - (phi + PI) / (2 * PI);
	result.uv.y = (theta + PI / 2) / PI;

	return true;
}

bool Sphere::intersectP(const Ray & ray) const {
	Vector3 v = ray.origin - center;
	Double d = v.lengthSqr() - radiusSqr;
	Double DdotV = ray.dir * v;

	if (DdotV > 0) return false;
	Double discr = DdotV * DdotV - d;
	if (discr <= 0) return false;
	discr = sqrt(discr);
	d = -DdotV - discr;
	d = (d < EPS) ? -DdotV + discr : d;
	if (d < EPS) return false;
	return true;
}

string Sphere::str() const {
	std::ostringstream s;
	s << getName() << "(pos = " << center.str() << ", r = " << radius << ")";
	return s.str();
}